﻿using System;

namespace KineticScroll
{
	internal sealed class Settings
	{
		#region Events

		/// <summary>
		/// Occurs when the value of RefreshInterval has changed.
		/// </summary>
		public event EventHandler RefreshIntervalChanged;

		/// <summary>
		/// Occurs when the value of Deceleration has changed.
		/// </summary>
		public event EventHandler DecelerationChanged;

		/// <summary>
		/// Occurs when the value of MaxVelocity has changed.
		/// </summary>
		public event EventHandler MaxVelocityChanged;

		#endregion Events

		#region Constants

		/// <summary>
		/// The default value of middle click enabled.
		/// </summary>
		public const bool MiddleClickEnabledDefaultValue = true;

		/// <summary>
		/// The default value of mouse wheel enabled.
		/// </summary>
		public const bool MouseWheelEnabledDefaultValue = false;

		/// <summary>
		/// The default value of the refresh interval.
		/// </summary>
		public const double RefreshIntervalDefaultValue = 10;

		/// <summary>
		/// The default value of deceleration.
		/// </summary>
		public const double DecelerationDefaultValue = 8;

		/// <summary>
		/// The default value of the maximum velocity.
		/// </summary>
		public const double MaxVelocityDefaultValue = 6;

		/// <summary>
		/// The default value of the mouse wheel acceleration factor.
		/// </summary>
		public const double MouseWheelAccelerationFactorDefaultValue = 1.2;

		#endregion Constants

		#region Variables

		private string _installedVersion;

		private bool _middleClickEnabled = Settings.MiddleClickEnabledDefaultValue;
		private bool _mouseWheelEnabled = Settings.MouseWheelEnabledDefaultValue;

		private double _refreshInterval = Settings.RefreshIntervalDefaultValue;
		private double _deceleration = Settings.DecelerationDefaultValue;
		private double _maxVelocity = Settings.MaxVelocityDefaultValue;

		private double _mouseWheelAccelerationFactor = Settings.MouseWheelAccelerationFactorDefaultValue;

		#endregion Variables

		#region Properties

		/// <summary>
		/// Gets or sets the installed version.
		/// </summary>
		/// <value>The installed version.</value>
		public string InstalledVersion
		{
			get
			{
				return _installedVersion;
			}
			set
			{
				_installedVersion = value;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether middle click kinetic scrolling is enabled.
		/// </summary>
		/// <value><c>true</c> if middle click kinetic scrolling is enabled; otherwise, <c>false</c>.</value>
		public bool MiddleClickEnabled
		{
			get
			{
				return _middleClickEnabled;
			}
			set
			{
				_middleClickEnabled = value;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether mouse wheel kinetic scrolling is enabled.
		/// </summary>
		/// <value><c>true</c> if mouse wheel kinetic scrolling is enabled; otherwise, <c>false</c>.</value>
		public bool MouseWheelEnabled
		{
			get
			{
				return _mouseWheelEnabled;
			}
			set
			{
				_mouseWheelEnabled = value;
			}
		}

		/// <summary>
		/// Gets or sets the refresh interval.
		/// </summary>
		/// <value>The refresh interval.</value>
		public double RefreshInterval
		{
			get
			{
				return _refreshInterval;
			}
			set
			{
				if (_refreshInterval != value)
				{
					_refreshInterval = value;
					OnRefreshIntervalChanged(EventArgs.Empty);
				}
			}
		}

		/// <summary>
		/// Gets or sets the deceleration.
		/// </summary>
		/// <value>The deceleration.</value>
		public double Deceleration
		{
			get
			{
				return _deceleration;
			}
			set
			{
				if (_deceleration != value)
				{
					_deceleration = value;
					OnDecelerationChanged(EventArgs.Empty);
				}
			}
		}

		/// <summary>
		/// Gets or sets the max velocity.
		/// </summary>
		/// <value>The max velocity.</value>
		public double MaxVelocity
		{
			get
			{
				return _maxVelocity;
			}
			set
			{
				if (_maxVelocity != value)
				{
					_maxVelocity = value;
					OnMaxVelocityChanged(EventArgs.Empty);
				}
			}
		}

		/// <summary>
		/// Gets or sets the mouse wheel acceleration factor.
		/// </summary>
		/// <value>The mouse wheel acceleration factor.</value>
		public double MouseWheelAccelerationFactor
		{
			get
			{
				return _mouseWheelAccelerationFactor;
			}
			set
			{
				_mouseWheelAccelerationFactor = value;
			}
		}

		#endregion Properties

		#region Singleton Implementation

		private static Settings _instance;

		/// <summary>
		/// Gets the instance.
		/// </summary>
		/// <value>The instance.</value>
		public static Settings Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new Settings();
				}
				return _instance;
			}
		}

		#endregion Singleton Implementation

		#region Constructor

		private Settings()
		{
		}

		#endregion Constructor

		#region Event Methods

		/// <summary>
		/// Raises the <see cref="E:RefreshIntervalChanged"/> event.
		/// </summary>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnRefreshIntervalChanged(EventArgs e)
		{
			EventHandler changed = RefreshIntervalChanged;
			if (changed != null)
			{
				changed(this, e);
			}
		}

		/// <summary>
		/// Raises the <see cref="E:DecelerationChanged"/> event.
		/// </summary>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnDecelerationChanged(EventArgs e)
		{
			EventHandler changed = DecelerationChanged;
			if (changed != null)
			{
				changed(this, e);
			}
		}

		/// <summary>
		/// Raises the <see cref="E:MaxVelocityChanged"/> event.
		/// </summary>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void OnMaxVelocityChanged(EventArgs e)
		{
			EventHandler changed = MaxVelocityChanged;
			if (changed != null)
			{
				changed(this, e);
			}
		}

		#endregion Event Methods
	}
}
